<?php require('pre.inc'); ?>
<script src="js/rawdeflate.js"></script>
<script src="js/rawinflate.js"></script>
<h1>Visualization Playground</h1>
<p id="load" style="display: inherit;">Loading <img src="load.gif" alt="Loading ..."/></p>
<div id="sparqlviz">
<div id="queryForm" style="display: none;" >
<p>Here you can create new queries to linked open aalto and visualize the outcome with different types of charts. Pick one of the examples or write your own query!</p>
<p id="prefix" style="font-size: 10px;"></p>
<div>
<select id="querySelect">
<option value="-1">New query</option>
<option value="0">Course distribution example</option>
<option value="1">Course language example</option>
<option value="2">Publication count example</option>
<option value="3">Courses dates example</option>
</select>
</div>
<textarea id="area" style="width:400px; height:150px;">
## Write a new query
SELECT ?anything (count(?you) as ?pop) WHERE {
?like rdf:type ?fancy ; rdfs:label ?anything.
?you foaf:topic_interest ?like.}
GROUP BY ?anything
HAVING(count(?you) > 5)
</textarea>
<div>
<button id="query">Visualize</button>
</div>
</div>
<div id="chartHolder">
<div id="editChart" style="visibility:hidden;"><a onclick='openEditor()'>Edit this visualization</a> | <a onclick='editQuery()'>Edit query</a> | <a onclick='newQuery()'>New query</a> | <a onclick='manualEdit()'>Manual edit</a></div>
<div><h2 id="title"></h2></div>
<div id='visualization' style="width:800px;height:300px;"> </div>
<div id="confJSON" style="display: none">
	<h2>Warning! Experimental feature!</h2>
	<div id="editMe" style="width:800px;height:100px;"></div>
</div>
</div>
<div style="visibility:hidden;" id="querycopy"></div>
<div style="visibility:hidden;" id="urlcopy"></div>
</div>
<script>
var bgraph = new BGraph();	
var prefix = bgraph.getPrefixes();
var gJSON;
var wrapper;
var submittedQuery = "";
$('#prefix').html(bgraph.getPrefixList().replace(/\n/g,"<br/>"));

google.load("visualization", "1", {packages:["charteditor"],language: "en"});

google.setOnLoadCallback(function() {
	$('#load').css("display", "none");
	if(window.location.href.indexOf("?query=")>0) {
		var decodedQuery = decodeURIComponent(window.location.href.substr(window.location.href.indexOf("?query=")+7))
		$('#area').val(decodedQuery);
	 }
	 if(window.location.hash) {
		var decodedHash = decode(window.location.hash.substr(1));
		decodedData = decodedHash.substr(0,decodedHash.indexOf("?query="));
		decodedQuery = decodedHash.substr(decodedHash.indexOf("?query=")+7);	
		if(decodedData != null) {
			submitQuery(decodedQuery,decodedData);
			$('#load').css("display", "inherit");
		}
		else {
			alert("There seems to be something wrong with the url");
			newQuery();
		}
	   }
   else {
	   newQuery();
	} 
});

var queries = ["# This query selects all the departments\n# and counts the total number of courses\nSELECT ?dept (COUNT(?course) AS ?count ) { \n [ foaf:name ?dept ] aiiso:teaches ?course . \n FILTER(langMatches(lang(?dept), 'EN'))} \nGROUP BY ?dept \n ORDER BY ?count","# This query counts all the courses\n# which are lectured in different languages\nSELECT ?lang (COUNT(?course) AS ?count ) where { \n ?course dct:language ?lang . } \n GROUP BY ?lang \n ORDER BY DESC(?count)","# This query counts all contributors\n# and number of publications in certain year\nSELECT ?date (COUNT(?member) AS ?contributors ) \n (COUNT(DISTINCT ?publication) AS ?publications ) where { \n ?publication bibo:authorList ?list ; dct:date ?date. \n ?list  rdf:rest*/rdf:first  ?member . } \n GROUP BY ?date \n ORDER BY ?date","SELECT xsd:string(?month) (count(DISTINCT ?course) as ?Courses)\nwhere { ?course teach:arrangedAt [ical:dtstart ?start].}\nGROUP BY (substr(str(?start),6,2) as ?month)\nORDER BY ?month"];

$('#querySelect').change(function() {
	decodedData = null; wrapper = null;
	if($('#querySelect option:selected').val()<0) {
	$('#area').val("## Write a new query\nSELECT ?anything (count(?you) as ?pop) WHERE {\n?like rdf:type ?fancy ; rdfs:label ?anything.\n?you foaf:topic_interest ?like.}\nGROUP BY ?anything\nHAVING(count(?you) > 5)");
	}
	else {
    $('#area').val(queries[$('#querySelect option:selected').val()]);
	}
});
      
function ajaxQuery(q) {
	return $.ajax({url: "http://data.aalto.fi/sparql?query="+encodeURIComponent(prefix+q)+"&format=json"});
}

function submitQuery(queryString,decodedData) {
	ajaxQuery(queryString).done(function(data) {
	//FIXME: comment this out
	//data = $.parseJSON(data); // For debugging only
	$('#load').css("display", "none");
	if(data.results.bindings.length>0) {
		submittedQuery = queryString;
		var gTable = new google.visualization.DataTable(bgraph.SparqlJSON2GoogleJSON(data));
		gJSON = gTable.toJSON();
		
		if(decodedData != null) initDecoded(decodedData);
		else init();
		
	} else { gJSON = null;
	alert("SPARQL-query did not return any results");
	$('#queryForm').css("display", "inherit");
}
}).fail(function(request, status, error) { 
	alert(request.responseText);
	$('#load').css("display", "none");
	$('#queryForm').css("display", "inherit"); 
});
}

$('#query').click(function() {
  var q = $("#area").val();
  $('#queryForm').css("display", "none");
  $('#load').css("display", "inherit");
  if(wrapper!=null) submitQuery(q,wrapper.toJSON());
  else if(decodedData != null) submitQuery(q,decodedData);
  else submitQuery(q);
  return false;
});

function init() {
  wrapper = new google.visualization.ChartWrapper({
    chartType: 'Table',
    dataTable: new google.visualization.DataTable(gJSON),
    options: {'title': 'Linked open aalto visualization'},
    containerId: 'visualization'
  });
   openEditor();
}

function initDecoded(decodedData) {
	$('#editChart').css("visibility", "visible");
	$('#chartHolder').css("display", "inherit");
	$('#queryForm').css("display", "none");
	wrapper = new google.visualization.ChartWrapper(decodedData);
	wrapper.setDataTable(gJSON);
	drawWrapper();
}

function b64en(e){var t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var n,r,i,s,o,u,a,f,l=0,c=0,h="",p=[];if(!e){return e}do{n=e.charCodeAt(l++);r=e.charCodeAt(l++);i=e.charCodeAt(l++);f=n<<16|r<<8|i;s=f>>18&63;o=f>>12&63;u=f>>6&63;a=f&63;p[c++]=t.charAt(s)+t.charAt(o)+t.charAt(u)+t.charAt(a)}while(l<e.length);h=p.join("");var d=e.length%3;return(d?h.slice(0,d-3):h)+"===".slice(d||3)}
function encode(str) { return b64en(RawDeflate.deflate(unescape(encodeURIComponent(str))));}

function b64de(e){var t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var n,r,i,s,o,u,a,f,l=0,c=0,h="",p=[];if(!e){return e}e+="";do{s=t.indexOf(e.charAt(l++));o=t.indexOf(e.charAt(l++));u=t.indexOf(e.charAt(l++));a=t.indexOf(e.charAt(l++));f=s<<18|o<<12|u<<6|a;n=f>>16&255;r=f>>8&255;i=f&255;if(u==64){p[c++]=String.fromCharCode(n)}else if(a==64){p[c++]=String.fromCharCode(n,r)}else{p[c++]=String.fromCharCode(n,r,i)}}while(l<e.length);h=p.join("");return h}
function decode(str) { return decodeURIComponent(escape(RawDeflate.inflate(b64de(str))));}

function openEditor() {
      // Handler for the "Open Editor" button.
      var editor = new google.visualization.ChartEditor();

      google.visualization.events.addListener(editor, 'ok',
        function() {
          wrapper = editor.getChartWrapper();
          var packed = encode(wrapper.toJSON());
          var hashLocation =  window.location.protocol + '//' + window.location.host + "/chart"+"#"+packed;
          $("#urlcopy").html("<p>Publish this visualization by linking to this <a href='"+hashLocation+"'>url location</a><br/>(Query will be lost but the chart will be rendered much faster from the resultset)</p>");
          drawWrapper();
      });
      
      google.visualization.events.addListener(editor, 'cancel',
        function() {
		if(wrapper!=null) {
			drawWrapper();
		} else newQuery();
		});
      
      editor.openDialog(wrapper);
 }
 
 // Draws wrapper to visualization div
 function drawWrapper() {
    $('#editChart').css("visibility", "visible");
	$('#chartHolder').css("display", "inherit");
	$('#urlcopy').css("visibility", "visible");
	$('#confJSON').css("display", "none");
	wrapper.draw(document.getElementById('visualization'));
	var title = wrapper.getChartName();
	if(title != null && title.length>1) $('#title').html(title);
	else  $('#title').html("");
	createHash();
 }
 
 
 // Removes nulls and empty strings
 function removeNulls(data) {
	for (var key in data) {
        if(!data[key] || data[key].length == 0) delete data[key];
        else if (typeof data[key] == "object") removeNulls(data[key]);    
    }

}
// Removes empty object
function removeEmptyObjects(data) {
	for (var key in data) {
        if(data[key] instanceof Object && Object.keys(data[key]).length === 0) delete data[key];
        else if (typeof data[key] == "object") removeEmptyObjects(data[key]);    
    }
}
 
 // Creates neat hash from google chart wrapper and sparql-query
 function createHash() {
		var wrapJSON = $.parseJSON(wrapper.toJSON());
		delete wrapJSON["dataTable"];
		removeNulls(wrapJSON);
		removeEmptyObjects(wrapJSON);
		var packed = JSON.stringify(wrapJSON);
		packed+="?query=";
		packed+=submittedQuery;			
		packed = encode(packed);
		window.location.hash="#"+packed; 
 }
 
 function manualEdit() {
	if(wrapper != null) {
		var op = wrapper.getOptions();
		removeNulls(op);
		removeEmptyObjects(op);
		$('#confJSON').css("display", "inherit");
		$('#editMe').html(JSON.stringify(op));
	}
 }
 
 $('#editMe').click(function() {
 this.contentEditable='true';
});
 
$('#editMe').focusout(function(){
	var obj = $.parseJSON(this.innerHTML);
	wrapper.setOptions(obj);
	drawWrapper();
});
 
 // encodes current wrapper and opens old query
 function editQuery() {
	if(submittedQuery != null && submittedQuery.length > 1) {
		$('#area').val(submittedQuery);
		$('#editChart').css("visibility", "hidden");
		$('#queryForm').css("display", "inherit");
		$('#chartHolder').css("display", "none");
		$('#confJSON').css("display", "none");
	} else { 
		alert("There seems to be something wrong with the query");
		newQuery();
}
}

// Deletes old wrapper and open new query form
 function newQuery() {
   decodedData = null;
   wrapper = null;
   window.location.hash="";
   $('#editChart').css("visibility", "hidden");
   $('#queryForm').css("display", "inherit");
   $('#chartHolder').css("display", "none");
   $('#confJSON').css("display", "none");
 }
</script>
<?php require('post.inc'); ?>

